# -*- coding: utf-8 -*-

"""此模块用于对训练数据进行聚类, 筛选出无标签数据中的
符合水军特征的用户
"""

import os
import sys
sys.path.append('../')
import sklearn
import pandas as pd
import numpy as np
import pickle
from io import BytesIO
from sklearn.cluster import KMeans
from sklearn.externals import joblib
from sklearn.mixture import GaussianMixture
from sklearn.preprocessing import normalize
from model.default import (
    cluster_one_model,
    cluster_two_model,
    cluster_three_model,
    cluster_gaussian_params
)

# debug settings
# pd.np.set_printoptions(threshold=pd.np.NaN)
first_features = ['fan_increase_rate', 'follow_increase_rate', 'fan_feature', 'follow_fan_ratio']
second_features = ['last_tweet_long']
third_features = ['time_repeats', 'label_repeats', 'at_ratio', 'v_sunshine']

def __first_k_mean(data, n_clusters=2, n_init=2, n_jobs=-1, algorithm='auto', tol=1e-6):
    km = KMeans(
            n_clusters=n_clusters, 
            n_init=n_init, 
            algorithm=algorithm, 
            max_iter=5000, 
            n_jobs=n_jobs, 
            random_state=1024,
            tol=tol
        )
    rsl = km.fit(data)

    print('保存第一层聚类模型于 %s' % cluster_one_model)
    joblib.dump(km, cluster_one_model)
    return rsl.labels_


def __second_k_mean(data, n_clusters=2, n_init=2, n_jobs=-1, algorithm='full', tol=1e-6):
    km = KMeans(
            n_clusters=n_clusters, 
            n_init=n_init, 
            n_jobs=n_jobs, 
            algorithm=algorithm, 
            random_state=1024, 
            max_iter=2048
        )
    
    rsl = km.fit(data)
    print('保存第二层聚类模型于 %s' % cluster_two_model)
    joblib.dump(km, cluster_two_model)
    return rsl.labels_


def __third_gaussian_mixture(data, n=2, covariance_type='tied', max_iter=5000, init_params='kmeans', tol=1e-6, issave=False):
    features = data.shape[1]
    if not issave:
        try:
            with open(cluster_gaussian_params, mode='rb') as fp:
                params = pickle.load(fp)
                weights_init = params['weightInit']
                means_init = params['meansInit']
            print('Loading Gaussian clustering initial weight && mean parameters.')
        except:
            print('Failure! Initial Randomly.')
            weights_init = np.random.rand()
            means_init = np.random.normal(0, 1, (n,features))  # 为模型参数初始化均值, 使用均值为0, 方差为.5的高斯分布初始化
    else:
        weights_init = np.random.rand()
        means_init = np.random.normal(0, 1, (n,features))

    gm = GaussianMixture(
            n_components=n, 
            max_iter=max_iter, 
            init_params=init_params, 
            covariance_type=covariance_type,
            weights_init=[weights_init, 1-weights_init],
            means_init=means_init,
            tol=tol,
            n_init=n
        ).fit(data)
    labels = gm.predict(data)

    print('保存第三层聚类模型于 %s' % cluster_three_model)
    joblib.dump(gm, cluster_three_model)
    if issave:
        print('保存高斯混合模型参数到 %s' % cluster_gaussian_params)
        with open(cluster_gaussian_params, mode='wb+') as fp:
            pickle.dump({'weightInit': weights_init, 'meansInit': means_init}, fp)
    return labels


# def train(data, issave=False):
#     first_label = __first_k_mean(data[first_features].values)
#     # data.insert(data.shape[1], 'label', first_label)
#     # return data
#     data2 = data[first_label==0]
#     second_label = __second_k_mean(data2[second_features].values)
#     data3 = data2[second_label==0]
#     third_label = __third_gaussian_mixture(data3[third_features].values, issave=issave)
#     rsl = data3[third_label == 1]
#     return rsl


def train(data, issave=False):
    first_label = __first_k_mean(data[first_features].values)
    label1 = 1 if len(first_label[first_label==1]) > len(first_label[first_label==0]) else 0 
    data2 = data[first_label==label1]

    second_label = __second_k_mean(data2[second_features].values)
    label2 = 1 if len(second_label[second_label==1]) > len(second_label[second_label==0]) else 0
    data3 = data2[second_label==label2]
    
    third_label = __third_gaussian_mixture(data3[third_features].values, issave=issave)
    label3 = 0 if len(third_label[third_label==1]) > len(third_label[third_label==0]) else 1
    rsl = data3[third_label == label3]
    return rsl


def predict(data):
    cluster1 = joblib.load(cluster_one_model)
    cluster2 = joblib.load(cluster_two_model)
    cluster3 = joblib.load(cluster_three_model)
    
    first_label = cluster1.predict(data[first_features].values)
    label1 = 1 if len(first_label[first_label==1]) > len(first_label[first_label==0]) else 0 
    data2 = data[first_label==label1]

    second_label = cluster2.predict(data2[second_features].values)
    label2 = 1 if len(second_label[second_label==1]) > len(second_label[second_label==0]) else 0
    data3 = data2[second_label==label2]

    third_label = cluster3.predict(data3[third_features].values)
    label3 = 0 if len(third_label[third_label==1]) > len(third_label[third_label==0]) else 1
    rsl = data3[third_label == label3]
    return rsl


